home *** CD-ROM | disk | FTP | other *** search
/ Practical Internet 2002 February / Practical Internet February 2002.iso / pc / Software / Browsing / httrack-3.09e2.exe / {app} / src / htsname.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-11-07  |  40.3 KB  |  1,218 lines

  1. /* ------------------------------------------------------------ */
  2. /*
  3. HTTrack Website Copier, Offline Browser for Windows and Unix
  4. Copyright (C) Xavier Roche and other contributors
  5.  
  6. This program is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU General Public License
  8. as published by the Free Software Foundation; either version 2
  9. of the License, or any later version.
  10.  
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with this program; if not, write to the Free Software
  18. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  19.  
  20.  
  21. Important notes:
  22.  
  23. - We hereby ask people using this source NOT to use it in purpose of grabbing
  24. emails addresses, or collecting any other private information on persons.
  25. This would disgrace our work, and spoil the many hours we spent on it.
  26.  
  27.  
  28. Please visit our Website: http://www.httrack.com
  29. */
  30.  
  31.  
  32. /* ------------------------------------------------------------ */
  33. /* File: httrack.c subroutines:                                 */
  34. /*       savename routine (compute output filename)             */
  35. /* Author: Xavier Roche                                         */
  36. /* ------------------------------------------------------------ */
  37.  
  38. #include "htsname.h"
  39.  
  40. /* specific definitions */
  41. #include "htsbase.h"
  42. #include "htstools.h"
  43. #include "htsmd5.h"
  44. #include <stdio.h>
  45. #include <stdlib.h>
  46. #include <ctype.h>
  47. /* END specific definitions */
  48.  
  49. #undef test_flush
  50. #define test_flush if (opt->flush) { fflush(opt->log); fflush(opt->errlog); }
  51.  
  52. #define ADD_STANDARD_PATH \
  53.     {  /* ajout nom */\
  54.       char buff[HTS_URLMAXSIZE*2];\
  55.       buff[0]='\0';\
  56.       strncat(buff,start_pos,(int) nom_pos - (int) start_pos);\
  57.       url_savename_addstr(save,buff);\
  58.     }
  59.  
  60. #define ADD_STANDARD_NAME(shortname) \
  61.     {  /* ajout nom */\
  62.       char buff[HTS_URLMAXSIZE*2];\
  63.       standard_name(buff,dot_pos,nom_pos,fil_complete,(shortname));\
  64.       url_savename_addstr(save,buff);\
  65.     }
  66.  
  67.  
  68. /* Avoid stupid DOS system folders/file such as 'nul' */
  69. /* Based on linux/fs/umsdos/mangle.c */
  70. static const char *hts_tbdev[] =
  71. {
  72.     "/prn", "/con", "/aux", "/nul",
  73.     "/lpt1", "/lpt2", "/lpt3", "/lpt4",
  74.     "/com1", "/com2", "/com3", "/com4",
  75.     "/clock$",
  76.     "/emmxxxx0", "/xmsxxxx0", "/setverxx",
  77.     ""
  78. };
  79.  
  80.  
  81.  
  82. // forme le nom du fichier α sauver (save) α partir de fil et adr
  83. // systΦme intelligent, qui renomme en cas de besoin (exemple: deux INDEX.HTML et index.html)
  84. int url_savename(char* adr_complete,char* fil_complete,char* save,char* former_adr,char* former_fil,char* referer_adr,char* referer_fil,httrackp* opt,lien_url** liens,int lien_tot,lien_back* back,int back_max,cache_back* cache,hash_struct* hash,int ptr,int numero_passe) {
  85.   char newfil[HTS_URLMAXSIZE*2];   /* ="" */
  86.   char* fil;
  87.   char* adr;
  88.   char* print_adr;
  89.   char *start_pos=NULL,*nom_pos=NULL,*dot_pos=NULL;  // Position nom et point
  90.   // pour changement d'extension ou de nom (content-disposition)
  91.   int ext_chg=0;
  92.   char ext[256];
  93.   //CLEAR
  94.   newfil[0]=ext[0]='\0';
  95.  
  96.   // effacer save
  97.   save[0]='\0';
  98.   // fil
  99.   fil = fil_complete;
  100.   // et adr (sauter user/pass)
  101.   // on prend le parti de mettre les fichiers avec login/pass au mΩme endroit que si ils
  102.   // Θtaient capturΘs sans ces paramΦtres
  103.   // c'est pour cette raison qu'on ignore totalement adr_complete (mΩme pour la recherche en table de hachage)
  104.   adr=jump_identification(adr_complete);
  105.  
  106.   // α afficher sans ftp://
  107.   print_adr=jump_protocol(adr);
  108.  
  109.   // court-circuit pour lien primaire
  110.   if (strnotempty(adr)==0) {
  111.     if (strcmp(fil,"primary")==0) {
  112.       strcat(save,"primary.html");
  113.       return 0;
  114.     }
  115.   }
  116.  
  117.  
  118.   // vΘrifier que le nom n'a pas dΘja ΘtΘ calculΘ (si oui le renvoyer tel que)
  119.   // vΘrifier que le nom n'est pas dΘja pris...
  120.   // NOTE: si on cherche /toto/ et que /toto est trouvΘ on le prend (et rΘciproquqment) ** // **
  121.   if (liens!=NULL) { 
  122.     register int i;
  123.  
  124. #if HTS_HASH
  125.     i=hash_read(hash,adr,fil_complete,1);      // recherche table 1 (adr+fil)
  126.     if (i>=0) {    // ok, trouvΘ
  127.       strcpy(save,liens[i]->sav);
  128.       return 0;
  129.     }
  130.     i=hash_read(hash,adr,fil_complete,2);      // recherche table 2 (former_adr+former_fil)
  131.     if (i>=0) {    // ok, trouvΘ
  132.       // copier location moved!
  133.       strcpy(adr_complete,liens[i]->adr);
  134.       strcpy(fil_complete,liens[i]->fil);
  135.       // et save
  136.       strcpy(save,liens[i]->sav);  // copier (formΘ α partir du nouveau lien!)
  137.       return 0;
  138.     }
  139. #else
  140.     for(i=lien_tot-1;i>=0;i--) {        
  141. #if HTS_CASSE
  142.       if ((strcmp(liens[i]->adr,adr)==0) && (strcmp(liens[i]->fil,fil_complete)==0))
  143. #else
  144.       if ((strfield2(liens[i]->adr,adr)) && (strfield2(liens[i]->fil,fil_complete)))
  145. #endif
  146.       {    // ok c'est le mΩme lien, adresse dΘja dΘfinie
  147.         strcpy(save,liens[i]->sav);
  148.         return 0;
  149.       }
  150.       if (liens[i]->former_adr) {     // tester ancienne loc?
  151. #if HTS_CASSE
  152.         if ((strcmp(liens[i]->former_adr,adr)==0) && (strcmp(liens[i]->former_fil,fil_complete)==0))
  153. #else
  154.         if ((strfield2(liens[i]->former_adr,adr)) && (strfield2(liens[i]->former_fil,fil_complete)))
  155. #endif
  156.         {
  157.           // copier location moved!
  158.           strcpy(adr_complete,liens[i]->adr);
  159.           strcpy(fil_complete,liens[i]->fil);
  160.           // et save
  161.           strcpy(save,liens[i]->sav);  // copier (formΘ α partir du nouveau lien!)
  162.           return 0;
  163.         }
  164.       }
  165.     }
  166. #endif
  167.  
  168.     // chercher sans / ou avec / dans former
  169.     {
  170.       char fil_complete_patche[HTS_URLMAXSIZE*2];
  171.       strcpy(fil_complete_patche,fil_complete);
  172.       // Version avec ou sans /
  173.       if (fil_complete_patche[strlen(fil_complete_patche)-1]=='/')
  174.         fil_complete_patche[strlen(fil_complete_patche)-1]='\0';
  175.       else
  176.         strcat(fil_complete_patche,"/");
  177. #if HTS_HASH
  178.       i=hash_read(hash,adr,fil_complete_patche,2);      // recherche table 2 (former_adr+former_fil)
  179.       if (i>=0) {
  180.         // Θcraser fil et adr (pas former_fil?????)
  181.         strcpy(adr_complete,liens[i]->adr);
  182.         strcpy(fil_complete,liens[i]->fil);
  183.         // Θcrire save
  184.         strcpy(save,liens[i]->sav);
  185.         return 0;
  186.       }
  187. #else
  188.       // mΩme boucle en gros
  189.       for(i=lien_tot-1;i>=0;i--) {        
  190.         if (liens[i]->former_adr) {    // former-adr?
  191. #if HTS_CASSE
  192.           if ((strcmp(liens[i]->former_adr,adr)==0) && (strcmp(liens[i]->former_fil,fil_complete_patche)==0))
  193. #else
  194.           if ((strfield2(liens[i]->former_adr,adr)) && (strfield2(liens[i]->former_fil,fil_complete_patche)))
  195. #endif
  196.           {    // ok c'est le mΩme lien, adresse dΘja dΘfinie
  197.             // Θcraser fil et adr (pas former_fil?????)
  198.             strcpy(adr_complete,liens[i]->adr);
  199.             strcpy(fil_complete,liens[i]->fil);
  200.             // Θcrire save
  201.             strcpy(save,liens[i]->sav);
  202.             return 0;
  203.           }
  204.         }
  205.       }
  206. #endif
  207.     }
  208.   }
  209.  
  210.   // vΘrifier la non prΘsence de paramΦtres dans le nom de fichier
  211.   // si il y en a, les supprimer (ex: truc.cgi?subj=aspirateur)
  212.   // nΘanmoins, gardΘ pour vΘrifier la non duplication (voir aprΦs)
  213.   {
  214.     char* a;
  215.     a=strchr(fil,'?');
  216.     if (a!=NULL) {
  217.       strncat(newfil,fil,(int) a-(int) fil);
  218.     } else {
  219.       strcpy(newfil,fil);
  220.     }
  221.     fil=newfil;
  222.   }
  223.   // dΘcoder %
  224.   strcpy(fil,unescape_http(fil));
  225.   /*
  226.   {
  227.     char tempo[HTS_URLMAXSIZE*2];
  228.     int i,j=0;
  229.     for (i=0;i<(int) strlen(fil);i++) {
  230.       if (fil[i]=='%') {
  231.         i++;
  232.         tempo[j++]=(char) ehex(fil+i);
  233.         i++;    // sauter 2 caractΦres finalement
  234.       } else
  235.         tempo[j++]=fil[i];
  236.     }
  237.     tempo[j++]='\0';
  238.     strcpy(fil,tempo);
  239.   }
  240.   */
  241.   
  242.   
  243.   /* replace shtml to html.. */
  244.   switch (ishtml(fil)) {       /* .html,.shtml,.. */
  245.   case 1:
  246.     if ( 
  247.       (strcmp(get_ext(fil),"html") != 0)
  248.       && (strcmp(get_ext(fil),"htm") != 0)
  249.       ) {
  250.       strcpy(ext,"html");
  251.       ext_chg=1;
  252.     }
  253.     break;
  254.     case 0:
  255.       if (!strnotempty(ext)) {
  256.         if (is_userknowntype(get_ext(fil))) {      // mime known by user
  257.           char mime[1024];
  258.           mime[0]=ext[0]='\0';
  259.           get_userhttptype(0,mime,get_ext(fil));
  260.           if (strnotempty(mime)) {
  261.             give_mimext(ext,mime);
  262.             if (strnotempty(ext)) {
  263.               ext_chg=1;
  264.             }
  265.           }
  266.         }
  267.       }
  268.       break;
  269.   }
  270.   
  271.  
  272.   // si option check_type activΘe
  273.   if ((opt->check_type) && (!ext_chg)) {
  274.     if ( (!strfield(adr_complete,"file://")) && (!strfield(adr_complete,"ftp://")) ) {
  275.       // tester type avec requΦte HEAD si on ne connait pas le type du fichier
  276.       if (!(   (opt->check_type==1) && (fil[strlen(fil)-1]=='/')   ))    // slash doit Ωtre html?
  277.       if (ishtml(fil)<0) { // on ne sait pas si c'est un html ou un fichier..
  278.         // lire dans le cache
  279.         htsblk r = cache_read(opt,cache,adr,fil,NULL);              // test uniquement
  280.         if (r.statuscode != -1) {  // pas d'erreur de lecture cache
  281.           char s[16]; s[0]='\0';
  282.           if ( (opt->debug>1) && (opt->log!=NULL) ) {
  283.             fspc(opt->log,"debug"); fprintf(opt->log,"Testing link type (from cache) %s%s"LF,adr_complete,fil_complete);
  284.             test_flush;
  285.           }
  286.           if (strnotempty(r.cdispo)) {        /* filename given */
  287.             ext_chg=2;      /* change filename */
  288.             strcpy(ext,r.cdispo);
  289.           }
  290.           else if (!may_unknown(r.contenttype)) {  // on peut patcher α priori?
  291.             give_mimext(s,r.contenttype);  // obtenir extension
  292.             if (strnotempty(s)>0) {        // on a reconnu l'extension
  293.               ext_chg=1;
  294.               strcpy(ext,s);
  295.             }
  296.           }
  297.           //
  298.         } else {          // test imposible dans le cache, faire une requΩte
  299.           //
  300. #if HTS_ANALYSTE
  301.           int hihp=_hts_in_html_parsing;
  302. #endif
  303.           int has_been_moved=0;
  304.           char curr_adr[HTS_URLMAXSIZE*2],curr_fil[HTS_URLMAXSIZE*2];
  305.           curr_adr[0]=curr_fil[0]='\0';
  306. #if HTS_ANALYSTE
  307.           _hts_in_html_parsing=2;  // test
  308. #endif
  309.           if ( (opt->debug>1) && (opt->log!=NULL) ) {
  310.             fspc(opt->log,"debug"); fprintf(opt->log,"Testing link type %s%s"LF,adr_complete,fil_complete);
  311.             test_flush;
  312.           }
  313.           strcpy(curr_adr,adr_complete);
  314.           strcpy(curr_fil,fil_complete);
  315.           // ajouter dans le backing le fichier en mode test
  316.           // savename: rien car en mode test
  317.           if (back_add(back,back_max,opt,cache,curr_adr,curr_fil,BACK_ADD_TEST,referer_adr,referer_fil,1,NULL)!=-1) {
  318.             int b;
  319.             b=back_index(back,back_max,curr_adr,curr_fil,BACK_ADD_TEST);         
  320.             if (b>=0) {
  321.               int petits_tours=0;
  322.               int get_test_request=0;       // en cas de bouclage sur soi mΩme avec HEAD, tester avec GET.. parfois c'est la cause des problΦmes
  323.               do {
  324.                 // temps α attendre, et remplir autant que l'on peut le cache (backing)
  325.                 if (back[b].status>0) back_wait(back,back_max,opt,cache,0);        
  326.                 if (ptr>=0)
  327.                   back_fillmax(back,back_max,opt,cache,liens,ptr,numero_passe,lien_tot);
  328.   
  329.                 // on est obligΘ d'appeler le shell pour le refresh..
  330. #if HTS_ANALYSTE
  331.                 {
  332.                   
  333.                   // Transfer rate
  334.                   engine_stats();
  335.                   
  336.                   // Refresh various stats
  337.                   HTS_STAT.stat_nsocket=back_nsoc(back,back_max);
  338.                   HTS_STAT.stat_errors=fspc(NULL,"error");
  339.                   HTS_STAT.nbk=backlinks_done(liens,lien_tot,ptr);
  340.                   HTS_STAT.nb=back_transfered(HTS_STAT.stat_bytes,back,back_max);
  341.  
  342.                   if (!hts_htmlcheck_loop(back,back_max,b,ptr,lien_tot,(int) (time_local()-HTS_STAT.stat_timestart),&HTS_STAT)) {
  343.                     return -1;
  344.                   } else if (_hts_cancel) {    // cancel 2 ou 1 (cancel parsing)
  345.                     back_delete(back,b);       // cancel test
  346.                   }
  347.                 }
  348. #endif
  349.                 
  350.                 
  351.                 // traitement des 304,303..
  352.                 if (back[b].status<=0) {
  353.                   if (    (back[b].r.statuscode==301)
  354.                        || (back[b].r.statuscode==302)
  355.                        || (back[b].r.statuscode==303)
  356.                        || (back[b].r.statuscode==307)
  357.                      ) {    // agh moved.. un tit tour de plus
  358.                     if ((petits_tours<5) && (former_adr) && (former_fil)) { // on va pas tourner en rond non plus!
  359.                       if ((int) strnotempty(back[b].r.location)) {    // location existe!
  360.                         char mov_url[HTS_URLMAXSIZE*2],mov_adr[HTS_URLMAXSIZE*2],mov_fil[HTS_URLMAXSIZE*2];
  361.                         mov_url[0]=mov_adr[0]=mov_fil[0]='\0';
  362.                         //
  363.                         strcpy(mov_url,back[b].r.location);    // copier URL
  364.                         if (ident_url_relatif(mov_url,curr_adr,curr_fil,mov_adr,mov_fil)>=0) {                        
  365.                           // si non bouclage sur soi mΩme, ou si test avec GET non testΘ
  366.                           if ((strcmp(mov_adr,curr_adr)) || (strcmp(mov_fil,curr_fil)) || (get_test_request==0)) {
  367.                             // bouclage?
  368.                             if ((!strcmp(mov_adr,curr_adr)) && (!strcmp(mov_fil,curr_fil)))
  369.                               get_test_request=1;     // faire requΦte avec GET
  370.  
  371.                             // recopier former_adr/fil?
  372.                             if ((former_adr) && (former_fil)) {
  373.                               if (strnotempty(former_adr)==0) {    // Pas dΘja notΘ
  374.                                 strcpy(former_adr,curr_adr);
  375.                                 strcpy(former_fil,curr_fil);
  376.                               }
  377.                             }
  378.  
  379.                             // ftp: stop!
  380.                             if (strfield(mov_url,"ftp://")) {    // ftp, ok on arrΩte
  381.                               has_been_moved = 1;
  382.                               back_delete(back,b);    // ok
  383.                               strcpy(curr_adr,mov_adr);
  384.                               strcpy(curr_fil,mov_fil);
  385.                             } else {
  386.                               char* methode;
  387.                               if (!get_test_request)
  388.                                 methode=BACK_ADD_TEST;      // tester avec HEAD
  389.                               else {
  390.                                 methode=BACK_ADD_TEST2;     // tester avec GET
  391.                                 if ( opt->errlog!=NULL ) {
  392.                                   fspc(opt->errlog,"warning"); fprintf(opt->errlog,"Loop with HEAD request (during prefetch) at %s%s"LF,curr_adr,curr_fil);
  393.                                   test_flush;
  394.                                 }                    
  395.                               }
  396.                               // Ajouter
  397.                               if (back_add(back,back_max,opt,cache,mov_adr,mov_fil,methode,referer_adr,referer_fil,1,NULL)!=-1) {    // OK
  398.                                 if ( (opt->debug>1) && (opt->errlog!=NULL) ) {
  399.                                   fspc(opt->errlog,"warning"); fprintf(opt->errlog,"(during prefetch) %s (%d) to link %s at %s%s"LF,back[b].r.msg,back[b].r.statuscode,back[b].r.location,curr_adr,curr_fil);
  400.                                   test_flush;
  401.                                 }                    
  402.                                 
  403.                                 // libΘrer emplacement backing actuel et attendre le prochain
  404.                                 back_delete(back,b);
  405.                                 strcpy(curr_adr,mov_adr);
  406.                                 strcpy(curr_fil,mov_fil);
  407.                                 b=back_index(back,back_max,curr_adr,curr_fil,methode);         
  408.                                 if (!get_test_request)
  409.                                   has_been_moved = 1;       // sinon ne pas forcer has_been_moved car non dΘplacΘ
  410.                                 petits_tours++;
  411.                                 //
  412.                               } else {// sinon on fait rien et on s'en va.. (ftp etc)
  413.                                 if ( (opt->debug>1)  && (opt->errlog)) {
  414.                                   fspc(opt->errlog,"debug"); fprintf(opt->errlog,"Warning: Savename redirect backing error at %s%s"LF,mov_adr,mov_fil);
  415.                                   test_flush;
  416.                                 } 
  417.                               }
  418.                             }
  419.                           } else {
  420.                             if ( opt->errlog!=NULL ) {
  421.                               fspc(opt->errlog,"warning"); fprintf(opt->errlog,"Unable to test %s%s (loop to same filename)"LF,adr_complete,fil_complete);
  422.                               test_flush;
  423.                             }
  424.                           }
  425.                           
  426.                         }
  427.                       }
  428.                     } else{  // arrΩter les frais
  429.                       if ( opt->errlog!=NULL ) {
  430.                         fspc(opt->errlog,"warning"); fprintf(opt->errlog,"Unable to test %s%s (loop)"LF,adr_complete,fil_complete);
  431.                         test_flush;
  432.                       }
  433.                     }
  434.                   }  // ok, leaving
  435.                 }
  436.                 
  437.               } while(back[b].status>0);
  438.               
  439.               // Si non dΘplacΘ, forcer type?
  440.               if (!has_been_moved) {
  441.                 if (back[b].r.statuscode!=-10) {    // erreur
  442.                   if (strnotempty(back[b].r.contenttype)==0)
  443.                     strcpy(back[b].r.contenttype,"text/html");    // message d'erreur en html
  444.                   // Finalement on, renvoie un erreur, pour ne toucher α rien dans le code
  445.                   // libΘrer emplacement backing
  446.                   /*if (opt->errlog!=NULL) {
  447.                     fspc(opt->errlog,0); fprintf(opt->errlog,"Error: (during prefetch) %s (%d) to link %s at %s%s"LF,back[b].r.msg,back[b].r.statuscode,back[b].r.location,curr_adr,curr_fil);
  448.                     test_flush;
  449.                   }                    
  450.                   back_delete(back,b);
  451.                   return -1;        // ERREUR (404 par exemple)
  452.                   */
  453.                 } 
  454.                 
  455.                 {            // pas d'erreur, changer type?
  456.                   char s[16]="";
  457.                   if (strnotempty(back[b].r.cdispo)) {        /* filename given */
  458.                     ext_chg=2;      /* change filename */
  459.                     strcpy(ext,back[b].r.cdispo);
  460.                   }
  461.                   else if ((!may_unknown(back[b].r.contenttype)) || (!get_ext(back[b].url_fil)) ) {  // on peut patcher α priori? (pas interdit ou pas de type)
  462.                     give_mimext(s,back[b].r.contenttype);  // obtenir extension
  463.                     if (strnotempty(s)>0) {    // on a reconnu l'extension
  464.                       ext_chg=1;
  465.                       strcpy(ext,s);
  466.                     }
  467.                   }
  468.                 }
  469.               }
  470.               // FIN Si non dΘplacΘ, forcer type?
  471.  
  472.               // libΘrer emplacement backing
  473.               back_delete(back,b);
  474.               
  475.               // --- --- ---
  476.               // oops, a ΘtΘ dΘplacΘ.. on recalcule en rΘcursif (osons!)
  477.               if (has_been_moved) {
  478.                 // copier adr, fil (optionnel, mais sinon marche pas pour le rip)
  479.                 strcpy(adr_complete,curr_adr);
  480.                 strcpy(fil_complete,curr_fil);
  481.                 // copier adr, fil
  482.                 
  483.                 return url_savename(curr_adr,curr_fil,save,NULL,NULL,referer_adr,referer_fil,opt,liens,lien_tot,back,back_max,cache,hash,ptr,numero_passe);
  484.               }
  485.               // --- --- ---
  486.               
  487.             }
  488.             
  489.           } else {
  490.             printf("PANIC! : Savename Crash adding error, unexpected error found.. [%d]\n",__LINE__);
  491. #if BDEBUG==1
  492.             printf("error while savename crash adding\n");
  493. #endif
  494.             if (opt->errlog) {
  495.               fspc(opt->errlog,"error"); fprintf(opt->errlog,"Unexpected savename backing error at %s%s"LF,adr,fil_complete);
  496.               test_flush;
  497.             } 
  498.             
  499.           }
  500.           // restaurer
  501. #if HTS_ANALYSTE
  502.           _hts_in_html_parsing=hihp;
  503. #endif
  504.         }  // cachΘ?
  505.       }
  506.     }
  507.   }
  508.  
  509.  
  510.  
  511.   // - - - DEBUT NOMMAGE - - -
  512.  
  513.   // Donner nom par dΘfaut?
  514.   if (fil[strlen(fil)-1]=='/')  {
  515.     if (!strfield(adr_complete,"ftp://"))
  516.       strcat(fil,DEFAULT_HTML);     // nommer page par dΘfaut!!
  517.     else {
  518.       if (!opt->proxy.active)
  519.         strcat(fil,DEFAULT_FTP);     // nommer page par dΘfaut (texte)
  520.       else
  521.         strcat(fil,DEFAULT_HTML);     // nommer page par dΘfaut (α priori ici html depuis un proxy http)
  522.     }
  523.   }
  524.   // Changer extension?
  525.   // par exemple, php3 sera sauvΘ en html, cgi en html ou gif, xbm etc.. selon les cas
  526.   if (ext_chg) {  // changer ext
  527.     char* a=fil+strlen(fil)-1;
  528.     if ( (opt->debug>1) && (opt->log!=NULL) ) {
  529.       fspc(opt->log,"debug");
  530.       if (ext_chg==1)
  531.         fprintf(opt->log,"Changing link extension %s%s to .%s"LF,adr_complete,fil_complete,ext);
  532.       else
  533.         fprintf(opt->log,"Changing link name %s%s to %s"LF,adr_complete,fil_complete,ext);
  534.       test_flush;
  535.     }
  536.     if (ext_chg==1) {
  537.       while(((int) a>(int) fil) && (*a!='.') && (*a!='/')) a--;
  538.       if (*a=='.') *a='\0';  // couper
  539.       strcat(fil,".");      // recopier point
  540.     } else {
  541.       while(((int) a>(int) fil) && (*a!='/')) a--;
  542.       if (*a=='/') a++;
  543.       *a='\0';
  544.    }
  545.     strcat(fil,ext);    // copier ext/nom
  546.   }
  547.  
  548.   // Rechercher premier / et dernier .
  549.   {  
  550.     char* a=fil+strlen(fil)-1;
  551.  
  552.     // passer structures
  553.     start_pos=fil;
  554.     while(((int) a>(int) fil) && (*a != '/') && (*a != '\\')) {
  555.       if (*a == '.')    // point? noter position
  556.         if (!dot_pos)
  557.           dot_pos=a;
  558.         a--;
  559.     }
  560.     if ((*a=='/') || (*a=='\\')) a++;
  561.     nom_pos = a;
  562.   }
  563.  
  564.   
  565.   // un nom de fichier est gΘnΘrΘ
  566.   // s'il existe dΘja, alors on le mofifie lΘgΦrement
  567.  
  568.   // ajouter nom du site Θventuellement en premier
  569.   if (opt->savename_type == -1) {    // utiliser savename_userdef! (%h%p/%n%q.%t)
  570.     char* a = opt->savename_userdef;
  571.     char* b = save;
  572.     /*char *nom_pos=NULL,*dot_pos=NULL;  // Position nom et point */
  573.     char tok;
  574.  
  575.     /*
  576.     {  // Rechercher premier /
  577.       char* a=fil+strlen(fil)-1;
  578.       // passer structures
  579.       while(((int) a>(int) fil) && (*a != '/') && (*a != '\\')) {
  580.         if (*a == '.')    // point? noter position
  581.         if (!dot_pos)
  582.           dot_pos=a;
  583.         a--;
  584.       }
  585.       if ((*a=='/') || (*a=='\\')) a++;
  586.       nom_pos = a;
  587.     }
  588.     */
  589.  
  590.     // Construire nom
  591.     while ((*a) && (((int) b - (int) save) < HTS_URLMAXSIZE ) ) {    // parser, et pas trop long..
  592.       if (*a == '%') {
  593.         int short_ver=0;
  594.         a++;
  595.         if (*a == 's') {
  596.           short_ver=1;
  597.           a++;
  598.         }
  599.         *b='\0';
  600.         switch(tok=*a++) {
  601.           case '[':            // %[param]
  602.             if (strchr(a,']')) {
  603.               char name[256];
  604.               char* c=name;
  605.               while(*a!=']') {
  606.                 *c++=*a++;
  607.               }
  608.               a++;
  609.               *c++='\0';
  610.               strcat(name,"=");           /* param=.. */
  611.               c=strchr(fil_complete,'?');
  612.               /* parameters exists */
  613.               if (c) {
  614.                 c=strstr(c,name);     /* finds param= */
  615.                 if (c) {
  616.                   c+=strlen(name);    /* jumps "param=" */
  617.                   while( (*c) && (*c!='&'))
  618.                     *b++=*c++;
  619.                 }
  620.               }
  621.             }
  622.           break;
  623.           case '%': *b++='%'; break;
  624.           case 'n':    // nom sans ext
  625.             if (dot_pos) {
  626.               if (!short_ver)    // Noms longs
  627.                 strncat(b,nom_pos,(int) dot_pos - (int) nom_pos);
  628.               else
  629.                 strncat(b,nom_pos,min((int) dot_pos - (int) nom_pos,8));
  630.             } else {
  631.               if (!short_ver)    // Noms longs
  632.                 strcpy(b,nom_pos);
  633.               else
  634.                 strncat(b,nom_pos,8);
  635.             }
  636.             b+=strlen(b);   // pointer α la fin
  637.             break;
  638.           case 'N':    // nom avec ext
  639.             // RECOPIE NOM + EXT
  640.             *b='\0';
  641.             if (dot_pos) {
  642.               if (!short_ver)    // Noms longs
  643.                 strncat(b,nom_pos,(int) dot_pos - (int) nom_pos);
  644.               else
  645.                 strncat(b,nom_pos,min((int) dot_pos - (int) nom_pos,8));
  646.             } else {
  647.               if (!short_ver)    // Noms longs
  648.                 strcpy(b,nom_pos);
  649.               else
  650.                 strncat(b,nom_pos,8);
  651.             }
  652.             b+=strlen(b);   // pointer α la fin
  653.             // RECOPIE NOM + EXT
  654.             *b='\0';
  655.             if (dot_pos) {
  656.               if (!short_ver)    // Noms longs
  657.                 strcpy(b,dot_pos+1);
  658.               else
  659.                 strncat(b,dot_pos+1,3);
  660.             } else {
  661.               if (!short_ver)    // Noms longs
  662.                 strcpy(b,DEFAULT_EXT);    // pas de..
  663.               else
  664.                 strcpy(b,DEFAULT_EXT_SHORT);    // pas de..
  665.             }
  666.             b+=strlen(b);   // pointer α la fin
  667.             //
  668.             break;
  669.           case 't':    // ext
  670.             *b='\0';
  671.             if (dot_pos) {
  672.               if (!short_ver)    // Noms longs
  673.                 strcpy(b,dot_pos+1);
  674.               else
  675.                 strncat(b,dot_pos+1,3);
  676.             } else {
  677.               if (!short_ver)    // Noms longs
  678.                 strcpy(b,DEFAULT_EXT);    // pas de..
  679.               else
  680.                 strcpy(b,DEFAULT_EXT_SHORT);    // pas de..
  681.             }
  682.             b+=strlen(b);   // pointer α la fin
  683.             break;
  684.           case 'p':    // path sans dernier /
  685.             *b='\0';
  686.             if (nom_pos != fil + 1) { // pas: /index.html (chemin nul)
  687.               if (!short_ver) {   // Noms longs
  688.                 strncat(b,fil,(int) nom_pos - (int) fil - 1);
  689.               } else {
  690.                 char pth[HTS_URLMAXSIZE*2],n83[HTS_URLMAXSIZE*2];
  691.                 pth[0]=n83[0]='\0';
  692.                 //
  693.                 strncat(pth,fil,(int) nom_pos - (int) fil - 1);
  694.                 long_to_83(n83,pth);
  695.                 strcpy(b,n83);
  696.               }
  697.             }
  698.             b+=strlen(b);   // pointer α la fin
  699.             break;
  700.           case 'h':    // host
  701.             *b='\0';
  702.             if (strcmp(adr_complete,"file://")==0) {
  703.               if (!short_ver)    // Noms longs
  704.                 strcpy(b,"localhost");
  705.               else
  706.                 strcpy(b,"local");
  707.             } else {
  708.               if (!short_ver)    // Noms longs
  709.                 strcpy(b,print_adr);
  710.               else
  711.                 strncat(b,print_adr,8);
  712.             }
  713.             b+=strlen(b);   // pointer α la fin
  714.             break;
  715.           case 'M':         /* host/address?query MD5 (128-bits) */
  716.             *b='\0';
  717.             {
  718.               char digest[32+2];
  719.               char buff[HTS_URLMAXSIZE*2];
  720.               digest[0]=buff[0]='\0';
  721.               strcpy(buff,adr);
  722.               strcat(buff,fil_complete);
  723.               domd5mem(buff,strlen(buff),digest,1,0);
  724.               strcpy(b,digest);
  725.             }
  726.             b+=strlen(b);   // pointer α la fin
  727.             break;
  728.           case 'Q': case 'q':         /* query MD5 (128-bits/16-bits) 
  729.                                          GENERATED ONLY IF query string exists! */
  730.             *b='\0';
  731.             strncat(b,url_md5(fil_complete),(tok == 'Q')?32:4);
  732.             b+=strlen(b);   // pointer α la fin
  733.             break;
  734.         }
  735.       } else
  736.         *b++=*a++;
  737.     }
  738.     *b++='\0';
  739.     //
  740.     // Types prΘdΘfinis
  741.     //
  742.  
  743.   } 
  744.   //
  745.   // Structure originale
  746.   else if (opt->savename_type%100==0) { 
  747.     /* recopier www.. */
  748.     if (opt->savename_type!=100) {  
  749.       if (((opt->savename_type/1000)%2)==0) {    // >1000 signifie "pas de www/"
  750.         if (strcmp(adr_complete,"file://")==0) {
  751.           //## if (*adr==lOCAL_CHAR) {
  752.           if (!opt->savename_83)  // noms longs
  753.             strcat(save,"localhost");
  754.           else
  755.             strcat(save,"local");
  756.         } else {
  757.           // adresse url
  758.           if (!opt->savename_83) {  // noms longs
  759.             strcat(save,print_adr);
  760.           } else {  // noms 8-3
  761.             if (strlen(print_adr)>4) {
  762.               if (strfield(print_adr,"www."))
  763.                 strncat(save,print_adr+4,8);
  764.               else
  765.                 strncat(save,print_adr,8);
  766.             } else strncat(save,print_adr,8);
  767.           }
  768.         }
  769.         if (*fil!='/') strcat(save,"/");
  770.       }
  771.     }
  772.   
  773. #if HTS_CASSE==0
  774.     hts_lowcase(save);
  775. #endif  
  776.         
  777.     /*
  778.     // ne sert α rien car a dΘja ΘtΘ filtrΘ normalement
  779.     if ((*fil=='.') && (*(fil+1)=='/'))          // ./index.html ** //
  780.       url_savename_addstr(save,fil+2);
  781.     else                                               // index.html ou /index.html
  782.       url_savename_addstr(save,fil);
  783.     if (save[strlen(save)-1]=='/') 
  784.       strcat(save,DEFAULT_HTML);     // nommer page par dΘfaut!!
  785. */
  786.  
  787.     /* add name */
  788.     ADD_STANDARD_PATH;
  789.     ADD_STANDARD_NAME(0);
  790.  
  791.   }
  792.   //
  793.   // Structure html/image
  794.   else {    
  795.     // dossier "web" ou "www.xxx" ?
  796.     if (((opt->savename_type/1000)%2)==0) {    // >1000 signifie "pas de www/"
  797.       if ((opt->savename_type/100)%2) {
  798.         if (strcmp(adr_complete,"file://")==0) {
  799.         //## if (*adr==lOCAL_CHAR) {
  800.           if (!opt->savename_83)  // noms longs
  801.             strcat(save,"localhost/");
  802.           else
  803.             strcat(save,"local/");
  804.         } else {
  805.           // adresse url
  806.           if (!opt->savename_83) {  // noms longs
  807.             strcat(save,print_adr); strcat(save,"/");
  808.           } else {  // noms 8-3
  809.             if (strlen(print_adr)>4) {
  810.               if (strfield(print_adr,"www."))
  811.                 strncat(save,print_adr+4,8);
  812.               else
  813.                 strncat(save,print_adr,8);
  814.               strcat(save,"/");
  815.             } else { 
  816.               strncat(save,print_adr,8); strcat(save,"/");
  817.             }
  818.           }
  819.         }
  820.       } else {
  821.         strcat(save,"web/");    // rΘpertoire gΘnΘral
  822.       }
  823.     } 
  824.  
  825.     // si un html α coup s√r
  826.     if ( (ext_chg!=0) ? (ishtml_ext(ext)==1) : (ishtml(fil)==1) ) {
  827.       if (opt->savename_type%100==2) {  // html/
  828.         strcat(save,"html/");
  829.       }
  830.     } else {
  831.       if ((opt->savename_type%100==1) || (opt->savename_type%100==2)) {  // html & images
  832.         strcat(save,"images/");
  833.       }
  834.     }
  835.     
  836.     switch (opt->savename_type%100) {
  837.     case 4: case 5: {           // sΘparer par types
  838.       char* a=fil+strlen(fil)-1;
  839.       // passer structures
  840.       while(((int) a>(int) fil) && (*a != '/') && (*a != '\\')) a--;      
  841.       if ((*a=='/') || (*a=='\\')) a++;
  842.  
  843.       // html?
  844.       if ( (ext_chg!=0) ? (ishtml_ext(ext)==1) : (ishtml(fil)==1) ) {
  845.         if (opt->savename_type%100==5)
  846.           strcat(save,"html/");
  847.       } else {
  848.         char* a=fil+strlen(fil)-1;
  849.         while(((int) a>(int) fil) && (*a != '/') && (*a != '.')) a--;      
  850.         if (*a!='.')
  851.           strcat(save,"other");
  852.         else
  853.           strcat(save,a+1);
  854.         strcat(save,"/");
  855.       }
  856.       /*strcat(save,a);*/
  857.       /* add name */
  858.       ADD_STANDARD_NAME(0);
  859.             }
  860.       break;
  861.     case 99: {                  // 'codΘ' .. c'est un gadget
  862.       int i;
  863.       int j;
  864.       char* a;
  865.       char C[]="ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-";
  866.       int L;
  867.       // pseudo-CRC sur fil et adr pour initialiser gΘnΘrateur alΘatoire..
  868.       unsigned int s=0;
  869.       L=strlen(C);
  870.       for(i=0;i<(int) strlen(fil_complete);i++) {
  871.         s+=(unsigned int) fil_complete[i];
  872.       }
  873.       for(i=0;i<(int) strlen(adr_complete);i++) {
  874.         s+=(unsigned int) adr_complete[i];
  875.       }
  876.       srand(s);
  877.       
  878.       j=strlen(save);
  879.       for(i=0;i<8;i++) {
  880.         char c=C[(rand()%L)];
  881.         save[i+j]=c;
  882.       }
  883.       save[i+j]='\0';
  884.       // ajouter extension
  885.       a=fil+strlen(fil)-1;
  886.       while(((int) a>(int) fil) && (*a != '/') && (*a != '.')) a--;
  887.       if (*a=='.') {
  888.         strcat(save,a);    // ajouter
  889.       }
  890.              } 
  891.       break;
  892.     default: {   // noms sans les noms des rΘpertoires
  893.       // ne garder que le nom, pas la structure
  894.       /*
  895.       char* a=fil+strlen(fil)-1;
  896.       while(((int) a>(int) fil) && (*a != '/') && (*a != '\\')) a--;      
  897.       if ((*a=='/') || (*a=='\\')) a++;
  898.       strcat(save,a);
  899.       */
  900.  
  901.       /* add name */
  902.       ADD_STANDARD_NAME(0);
  903.             }
  904.       break;
  905.     }
  906.  
  907. #if HTS_CASSE==0
  908.     hts_lowcase(save);
  909. #endif  
  910.  
  911.     if (save[strlen(save)-1]=='/') 
  912.       strcat(save,DEFAULT_HTML);     // nommer page par dΘfaut!!
  913.   }
  914.  
  915.  
  916.   // vΘrifier qu'on ne doit pas forcer l'extension
  917.   // par exemple, asp sera sauvΘ en html, cgi en html ou gif, xbm etc.. selon les cas
  918.   /*if (ext_chg) {
  919.     char* a=save+strlen(save)-1;
  920.     while(((int) a>(int) save) && (*a!='.') && (*a!='/')) a--;
  921.     if (*a=='.') *a='\0';  // couper
  922.     // recopier extension
  923.     strcat(save,".");
  924.     strcat(save,ext);    // copier ext
  925.   }*/
  926.   // de mΩme en cas de manque d'extension on en place une de maniΦre forcΘe..
  927.   // cela Θvite les /chez/toto et les /chez/toto/index.html incompatibles
  928.   if (opt->savename_type != -1) {
  929.     char* a=save+strlen(save)-1;
  930.     while(((int) a>(int) save) && (*a!='.') && (*a!='/')) a--;
  931.     if (*a!='.') {   // agh pas de point
  932.       //strcat(save,".none");                 // a Θviter
  933.       strcat(save,".html");                   // prΘfΘrable!
  934.       if ( (opt->debug>1) && (opt->errlog!=NULL) ) {
  935.         fspc(opt->errlog,"warning"); fprintf(opt->errlog,"Default HTML type set for %s%s"LF,adr_complete,fil_complete);
  936.         test_flush;
  937.       }
  938.     }
  939.   }
  940.  
  941.   // effacer pass au besoin pour les autentifications
  942.   // (plus la peine : masquΘ au dΘbut)
  943. /*
  944.   {
  945.     char* a=jump_identification(save);
  946.     if (a!=save) {
  947.       char tempo[HTS_URLMAXSIZE*2];
  948.       char *b;
  949.       tempo[0]='\0';
  950.       strcpy(tempo,"[");
  951.       b=strchr(save,':');
  952.       if (!b) b=strchr(save,'@');
  953.       if (b)
  954.         strncat(tempo,save,(int) b-(int) a);
  955.       strcat(tempo,"]");
  956.       strcat(tempo,a);
  957.       strcpy(save,a);
  958.     }
  959.   }
  960. */
  961.  
  962.   // Θviter les / au dΘbut (cause: N100)
  963.   if (save[0]=='/') {
  964.     char tempo[HTS_URLMAXSIZE*2];
  965.     strcpy(tempo,save+1);
  966.     strcpy(save,tempo);
  967.   }
  968.  
  969.   // changer les ~,:,",*,? en _ pour sauver sur disque
  970.   hts_replace(save,'~','_');  // interdit sous unix (~foo)
  971.   //
  972.   hts_replace(save,'\\','_');
  973.   hts_replace(save,':','_');  // interdit sous windows
  974.   hts_replace(save,'*','_');  // interdit sous windows
  975.   hts_replace(save,'?','_');  // doit pas arriver!!
  976.   hts_replace(save,'\"','_');  // interdit sous windows
  977.   hts_replace(save,'<','_');  // interdit sous windows
  978.   hts_replace(save,'>','_');  // interdit sous windows
  979.   hts_replace(save,'|','_');  // interdit sous windows
  980.   //
  981.   hts_replace(save,'@','_');
  982.   //
  983.   { // Θliminer les // (comme ftp://)
  984.     char* a;
  985.     while( (a=strstr(save,"//")) ) *a='_';
  986.     // Eliminer chars spΘciaux
  987.     a=save -1 ;
  988.     while(*(++a))
  989.       if ( ((unsigned char)(*a) <= 31)
  990.           || ((unsigned char)(*a) == 127) )
  991.         *a='_';
  992.   }
  993.  
  994.    
  995. #if HTS_OVERRIDE_DOS_FOLDERS
  996.   /* Replace /foo/nul/bar by /foo/nul-/bar */
  997.   {
  998.     int i=0;
  999.     while(hts_tbdev[i][0]) {
  1000.       char* a=save;
  1001.       while((a=strstr(a,hts_tbdev[i]))) {
  1002.         switch ( (int) a[strlen(hts_tbdev[i])] ) {
  1003.         case '\0':
  1004.         case '/':  {
  1005.           char tempo[HTS_URLMAXSIZE*2]; tempo[0]='\0';
  1006.           strncat(tempo,save,(int) a - (int) save + strlen(hts_tbdev[i]));
  1007.           strcat(tempo,"-");
  1008.           strcat(tempo,a+strlen(hts_tbdev[i]));
  1009.           strcpy(save,tempo);
  1010.                    }
  1011.           break;
  1012.         }
  1013.         a+=strlen(hts_tbdev[i]);
  1014.       }
  1015.       i++;
  1016.     }
  1017.   }
  1018. #endif
  1019.  
  1020.   // conversion 8-3 .. y compris pour les rΘpertoires
  1021.   if (opt->savename_83) {
  1022.     char n83[HTS_URLMAXSIZE*2];
  1023.     long_to_83(n83,save);
  1024.     strcpy(save,n83);
  1025.   }
  1026.  
  1027.  
  1028.   /* ensure that there is no ../ (potential vulnerability) */
  1029.   fil_simplifie(save);
  1030.  
  1031.   // chemin primaire Θventuel A METTRE AVANT
  1032.   if (strnotempty(opt->path_html)) {
  1033.     char tempo[HTS_URLMAXSIZE*2];
  1034.     strcpy(tempo,opt->path_html);
  1035.     strcat(tempo,save);
  1036.     strcpy(save,tempo);
  1037.   }
  1038.  
  1039.  
  1040.   // vΘrifier que le nom n'est pas dΘja pris...
  1041.   if (liens!=NULL) { 
  1042.     int nom_ok;
  1043.     do {
  1044.       register int i;
  1045.       register int len;
  1046.       len=strlen(save);    // taille
  1047.       //
  1048.       nom_ok=1;  // α priori bon
  1049.       // on part de la fin pour optimiser, plus les opti de taille pour aller encore plus vite..
  1050. #if DEBUG_SAVENAME
  1051. printf("\nStart search\n");
  1052. #endif
  1053.  
  1054. #if HTS_HASH
  1055.       i=hash_read(hash,save,"",0);      // lecture type 0 (sav)
  1056.       if (i>=0)
  1057. #else
  1058.       for(i=lien_tot-1;i>=0;i--) {
  1059. #if DEBUG_SAVENAME
  1060. printf("%cParse: %d",13,i);
  1061. #endif
  1062.         
  1063.         if (liens[i]->sav_len==len) {    // mΩme taille de chaεne          
  1064. #if HTS_CASSE
  1065.           if (strcmp(liens[i]->sav,save)==0)    // existe dΘja
  1066. #else
  1067.           if (strfield2(liens[i]->sav,save))    // un tel nom existe dΘja
  1068. #endif
  1069. #endif
  1070.           {
  1071. #if HTS_CASSE
  1072.             if ((strcmp(liens[i]->adr,adr)==0) && (strcmp(liens[i]->fil,fil_complete)==0))
  1073. #else
  1074.             if ((strfield2(liens[i]->adr,adr)) && (strfield2(liens[i]->fil,fil_complete)))
  1075. #endif
  1076.             {    // ok c'est le mΩme lien, adresse dΘja dΘfinie
  1077.               //printf("Ok, %s\n",save);
  1078.               //i=lien_tot;    // sortir
  1079.               i=0;
  1080. #if DEBUG_SAVENAME
  1081. printf("\nOK ALREADY DEFINED\n",13,i);
  1082. #endif
  1083.             } else {  // utilisΘ par un AUTRE, changer de nom
  1084.               char tempo[HTS_URLMAXSIZE*2];
  1085.               char* a=save+strlen(save)-1;
  1086.               char* b;
  1087.               int n=2;       
  1088.               tempo[0]='\0';
  1089.  
  1090. #if DEBUG_SAVENAME
  1091. printf("\nWRONG CASE UNMATCH : \n%s\n%s, REDEFINE\n",liens[i]->fil,fil_complete);
  1092. #endif
  1093.               nom_ok=0;
  1094.               i=0;
  1095.               
  1096.               while(((int) a>(int) save) && (*a!='.') && (*a!='\\') && (*a!='/')) a--;
  1097.               if (*a=='.')
  1098.                 strncat(tempo,save,(int) a-(int) save);
  1099.               else
  1100.                 strcat(tempo,save);
  1101.               
  1102.               // tester la prΘsence d'un -xx (ex: index-2.html -> index-3.html)
  1103.               b=tempo+strlen(tempo)-1;
  1104.               while (isdigit((unsigned char)*b)) b--;
  1105.               if (*b=='-') {
  1106.                 sscanf(b+1,"%d",&n);
  1107.                 *b='\0';    // couper
  1108.                 n++;  // plus un
  1109.               }
  1110.               
  1111.               // en plus il faut gΘrer le 8-3 .. pas facile le client
  1112.               if (opt->savename_83) {
  1113.                 int max;
  1114.                 char* a=tempo+strlen(tempo)-1;
  1115.                 while(((int) a>(int) tempo) && (*a!='/')) a--;
  1116.                 if (*a=='/') a++;
  1117.                 max=8-1-nombre_digit(n);
  1118.                 if ((int) strlen(a)>max)
  1119.                   *(a+max)='\0';  // couper sinon il n'y aura pas la place!
  1120.               }
  1121.               
  1122.               // ajouter -xx (ex: index.html -> index-2.html)
  1123.               sprintf(tempo+strlen(tempo),"-%d",n);
  1124.               
  1125.               // ajouter extension
  1126.               if (*a=='.')
  1127.                 strcat(tempo,a);
  1128.               
  1129.               strcpy(save,tempo);
  1130.               
  1131.               //printf("switched: %s\n",save);
  1132.               
  1133.             }  // if
  1134. #if HTS_HASH
  1135.           }
  1136. #else
  1137.           }  // if
  1138.         }  // if sav_len
  1139.       }  // for
  1140. #endif
  1141. #if DEBUG_SAVENAME
  1142. printf("\nEnd search, %s\n",fil_complete);
  1143. #endif
  1144.     } while(!nom_ok);
  1145.     
  1146.   }
  1147.   
  1148.   //printf("'%s' %s %s\n",save,adr,fil);
  1149.       
  1150.   return 0;
  1151. }
  1152.  
  1153. /* nom avec md5 urilisΘ partout */
  1154. void standard_name(char* b,char* dot_pos,char* nom_pos,char* fil_complete,int short_ver) {
  1155.   b[0]='\0';
  1156.   /* Nom */
  1157.   if (dot_pos) {
  1158.     if (!short_ver)    // Noms longs
  1159.       strncat(b,nom_pos,(int) dot_pos - (int) nom_pos);
  1160.     else
  1161.       strncat(b,nom_pos,min((int) dot_pos - (int) nom_pos,8));
  1162.   } else {
  1163.     if (!short_ver)    // Noms longs
  1164.       strcat(b,nom_pos);
  1165.     else
  1166.       strncat(b,nom_pos,8);
  1167.   }
  1168.   /* MD5 - 16 bits */
  1169.   strncat(b,url_md5(fil_complete),4);
  1170.   /* Ext */
  1171.   if (dot_pos) {
  1172.     strcat(b,".");
  1173.     if (!short_ver)    // Noms longs
  1174.       strcat(b,dot_pos+1);
  1175.     else
  1176.       strncat(b,dot_pos+1,3);
  1177.   } else {
  1178.     if (!short_ver)    // Noms longs
  1179.       strcat(b,DEFAULT_EXT);    // pas de..
  1180.     else
  1181.       strcat(b,DEFAULT_EXT_SHORT);    // pas de..
  1182.   }
  1183. }
  1184.  
  1185.  
  1186. /* Petit md5 */
  1187. char* url_md5(char* fil_complete) {
  1188.   static char digest[32+2];
  1189.   char* a;
  1190.   digest[0]='\0';
  1191.   a=strchr(fil_complete,'?');
  1192.   if (a) {
  1193.     if (strlen(a)) {
  1194.       char buff[HTS_URLMAXSIZE*2];
  1195.       a++;
  1196.       digest[0]=buff[0]='\0';
  1197.       strcat(buff,a);         /* query string MD5 */
  1198.       domd5mem(buff,strlen(buff),digest,1,0);
  1199.     }
  1200.   }
  1201.   return digest;
  1202. }
  1203.  
  1204. // interne α url_savename: ajoute une chaεne α une autre avec \ -> /
  1205. void url_savename_addstr(char* d,char* s) {
  1206.   int i=strlen(d);
  1207.   while(*s) {
  1208.     if (*s=='\\')  // remplacer \ par des /
  1209.       d[i++]='/';
  1210.     else
  1211.       d[i++]=*s;
  1212.     s++;
  1213.   }
  1214.   d[i]='\0';
  1215. }
  1216.  
  1217. #undef test_flush
  1218.